﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2012 Cell Cloud Team - cellcloudproject@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "CellStableHeaders.h"
#include "CellTalkService.h"
#include "CellTalkAcceptorHandler.h"
#include "CellTalkServiceDaemon.h"
#include "CellNonblockingAcceptor.h"
#include "CellSession.h"
#include "CellMessage.h"
#include "CellSpeaker.h"
#include "CellTalkListener.h"
#include "CellCellet.h"
#include "CellCloudGraph.h"
#include "CellNucleus.h"
#include "CellCelletSupervisor.h"
#include "CellPrimitive.h"
#include "CellTalkWebService.h"
#include "CellExecutorManager.h"
#include "CellExecutorService.h"
#include "CellFileExpress.h"
#include "CellLoggerManager.h"
#include "CellStringVector.h"
#include "CellUtil.h"

namespace cell
{

#define TALKSERVICE_PORT 7000

template<> TalkService* Singleton<TalkService>::ms_Singleton = NULL;

//-----------------------------------------------------------------------
TalkService* TalkService::getSingletonPtr(void)
{
	return ms_Singleton;
}
//-----------------------------------------------------------------------
TalkService& TalkService::getSingleton(void)
{
	assert(ms_Singleton);
	return (*ms_Singleton);  
}

//-----------------------------------------------------------------------
TalkService::TalkService(CloudGraph* cloudGraph)
	: mCloudGraph(cloudGraph)
	, mAcceptor(NULL)
	, mAcceptorHandler(NULL)
	, mProxy(NULL)
	, mDaemon(NULL)
	, mFlashAddon(NULL)
	, mWebService(NULL)
	, mPort(TALKSERVICE_PORT)
	, mExecutor(NULL)
	, mFileExpressServer(NULL)
	, mSpeakClosed(false)
{
}
//-----------------------------------------------------------------------
TalkService::~TalkService(void)
{
	mSpeakClosed = true;

	{
		CELL_LOCK_MUTEX(mSpeakerMutex);

		// 关闭 Speaker
		Speakers::iterator iter, end = mSpeakers.end();
		for (iter = mSpeakers.begin(); iter != end; ++iter)
		{
			Speaker* speaker = iter->second;

			// 挂断会话
			speaker->hangup();

			CELL_DELETE speaker;
		}
		mSpeakers.clear();
	}

	if (NULL != mFileExpressServer)
	{
		CELL_DELETE mFileExpressServer;
		mFileExpressServer = NULL;
	}

	if (NULL != mProxy)
	{
		mProxy->shutdown();

		CELL_DELETE mProxy;
		mProxy = NULL;
	}

	if (NULL != mExecutor)
	{
		ExecutorManager::getSingleton().destroyCachedThreadPool(mExecutor->getName());
		mExecutor = NULL;
	}
}
//---------------------------------------------------------------------------
bool TalkService::startup(void)
{
	if (NULL == mAcceptorHandler)
		mAcceptorHandler = CELL_NEW TalkAcceptorHandler(this);
	if (NULL == mAcceptor)
		mAcceptor = CELL_NEW NonblockingAcceptor();

	// 最大连接数
	mAcceptor->setMaxConnectNum(1024);

	// 定义包标识
	char head[4] = {0x20, 0x10, 0x11, 0x10};
	char tail[4] = {0x19, 0x78, 0x10, 0x04};
	mAcceptor->defineDataMark(head, 4, tail, 4);

	// 设置处理器
	mAcceptor->setHandler(mAcceptorHandler);

	bool succeeded = mAcceptor->bind(mPort);
	if (succeeded)
	{
		if (NULL == mDaemon)
			mDaemon = CELL_NEW TalkServiceDaemon(this);
		mDaemon->start();
	}

	// 启动附件
	startupAddons();

	// 激活 Web 服务
	// TODO activateWebService();

	mTick = Util::currentTimeMillis();

	return succeeded;
}
//---------------------------------------------------------------------------
void TalkService::shutdown(void)
{
	if (NULL != mAcceptor)
	{
		mAcceptor->latch = true;
	}

	// 停止附件
	shutdownAddons();

	// 停止 Web 服务
	// TODO deactivateWebService();

	if (NULL != mProxy)
	{
		mProxy->shutdown();

		CELL_DELETE mProxy;
		mProxy = NULL;
	}

	if (NULL != mAcceptor)
	{
		mAcceptor->unbind();

		CELL_DELETE mAcceptor;
		mAcceptor = NULL;
	}

	if (NULL != mAcceptorHandler)
	{
		CELL_DELETE mAcceptorHandler;
		mAcceptorHandler = NULL;
	}

	// 停止守护线程
	if (NULL != mDaemon)
	{
		LoggerManager::getSingleton().log("Close talk service daemon...");

		mDaemon->stop();
		while (mDaemon->isRunning())
		{
			Thread::sleep(10);
		}
		CELL_DELETE mDaemon;
		mDaemon = NULL;
	}

	if (NULL != mFileExpressServer)
	{
		mFileExpressServer->stopServer();

		CELL_DELETE mFileExpressServer;
		mFileExpressServer = NULL;
	}

	{
		// 清理 Session

		CELL_LOCK_MUTEX(mSessionMutex);

		SessionCertificates::iterator uiter, uend = mUnidentifiedSessions.end();
		for (uiter = mUnidentifiedSessions.begin(); uiter != uend; ++uiter)
		{
			Certificate* cert = uiter->second;
			CELL_DELETE cert;
		}
		mUnidentifiedSessions.clear();

		SessionContexts::iterator iter, end = mSessionContexts.end();
		for (iter = mSessionContexts.begin(); iter != end; ++iter)
		{
			TalkSessionContext* ctx = iter->second;
			CELL_DELETE ctx;
		}
		mSessionContexts.clear();

		SessionContextList::iterator citer, cend = mExpiredContexts.end();
		for (citer = mExpiredContexts.begin(); citer != cend; ++citer)
		{
			TalkSessionContext* ctx = (*citer);
			CELL_DELETE ctx;
		}
		mExpiredContexts.clear();
	}
}
//---------------------------------------------------------------------------
bool TalkService::prepared(void)
{
	return (NULL != mAcceptor);
}
//-----------------------------------------------------------------------
TalkServiceProfile TalkService::getProfile(void) const
{
	TalkServiceProfile profile;
	profile.maxCountNum = mAcceptor->getMaxConnectNum();
	profile.countNumSnapshot = mAcceptor->getConnectNum();
	return profile;
}
//-----------------------------------------------------------------------
inline void TalkService::setPort(uint16 port)
{
	mPort = port;
}
//-----------------------------------------------------------------------
inline uint16 TalkService::getPort(void) const
{
	return mPort;
}
//-----------------------------------------------------------------------
void TalkService::importProxyAddress(const Inet4AddressList& addressList)
{
	if (NULL == mProxy)
		mProxy = CELL_NEW TalkProxy();

	Inet4AddressList::const_iterator iter, end = addressList.end();
	for (iter = addressList.begin(); iter != end; ++iter)
	{
		mProxy->addHostAddress((*iter));
	}
}
//-----------------------------------------------------------------------
void TalkService::startProxy(void)
{
	if (NULL == mProxy)
		mProxy = CELL_NEW TalkProxy();

	mProxy->startup();
}
//-----------------------------------------------------------------------
void TalkService::stopProxy(void)
{
	if (NULL == mProxy)
		return;

	mProxy->shutdown();

	CELL_DELETE mProxy;
	mProxy = NULL;
}
//-----------------------------------------------------------------------
void TalkService::latch(void)
{
	if (NULL != mAcceptor)
	{
		mAcceptor->latch = true;
	}
}
//-----------------------------------------------------------------------
void TalkService::unlatch(void)
{
	if (NULL != mAcceptor)
	{
		mAcceptor->latch = false;
	}
}
//-----------------------------------------------------------------------
void TalkService::retrySpeaker(Speaker* speaker)
{
	if (mSpeakClosed)
		return;

	CELL_LOCK_MUTEX(mSpeakerMutex);

	Speakers::iterator iter = mLostSpeakers.find(speaker->getCelletIdentifier());
	if (iter == mLostSpeakers.end())
	{
		mLostSpeakers.insert(Speakers::value_type(speaker->getCelletIdentifier(), speaker));
	}
}
//-----------------------------------------------------------------------
void TalkService::doAction(ActionDelegate* delegate, ActionDialect* dialect)
{
	if (NULL == mExecutor)
	{
		mExecutor = ExecutorManager::getSingleton().createCachedThreadPool(
			"TalkServiceExecutor", 8, 32);
		mExecutor->addListener(this);
	}

	ActionDelegateWorker* worker = CELL_NEW ActionDelegateWorker(dialect, delegate);
	if (!mExecutor->execute(worker))
	{
		mExecutor->remove(worker);
		CELL_DELETE worker;
	}
}
//-----------------------------------------------------------------------
void TalkService::startSchedule(void)
{
	if (NULL == mDaemon)
	{
		mDaemon = CELL_NEW TalkServiceDaemon(this);
		mDaemon->start();
	}

	if (NULL == mExecutor)
	{
		mExecutor = ExecutorManager::getSingleton().createCachedThreadPool(
			"TalkServiceExecutor", 8, 32);
		mExecutor->addListener(this);
	}
}
//-----------------------------------------------------------------------
void TalkService::stopSchedule(void)
{
	// 关闭守护线程
	if (NULL != mDaemon)
	{
		mDaemon->stop();

		while (mDaemon->isRunning())
		{
			Thread::sleep(100);
		}

		CELL_DELETE mDaemon;
		mDaemon = NULL;
	}

	if (NULL != mExecutor)
	{
		mExecutor->removeListener(this);
		ExecutorManager::getSingleton().destroyCachedThreadPool(mExecutor->getName());
		mExecutor = NULL;
	}
}
//-----------------------------------------------------------------------
bool TalkService::call(const Inet4Address& address, const String& identifier)
{
	Speaker* speaker = NULL;

	{
		CELL_LOCK_MUTEX(mSpeakerMutex);

		Speakers::const_iterator iter = mSpeakers.find(identifier);
		if (iter == mSpeakers.end())
		{
			speaker = CELL_NEW Speaker(identifier);
			mSpeakers.insert(Speakers::value_type(identifier, speaker));
		}
		else
		{
			speaker = iter->second;
		}

		// 从丢失连接列表里移除
		iter = mLostSpeakers.find(identifier);
		if (iter != mLostSpeakers.end())
		{
			mLostSpeakers.erase(iter);
		}
	}

	bool ret = false;

	if (address.getPort() == 0)
	{
		// 设置端口
		Inet4Address addr(address.getHostAddress(), TALKSERVICE_PORT);

		// 连接
		ret = speaker->call(addr);
	}
	else
	{
		ret = speaker->call(address);
	}

	if (!ret)
	{
		CELL_LOCK_MUTEX(mSpeakerMutex);

		if (mLostSpeakers.find(identifier) == mLostSpeakers.end())
		{
			mLostSpeakers.insert(Speakers::value_type(identifier, speaker));
		}
	}

	return ret;
}
//-----------------------------------------------------------------------
void TalkService::hangup(const String& identifier)
{
	CELL_LOCK_MUTEX(mSpeakerMutex);

	Speakers::const_iterator iter = mLostSpeakers.find(identifier);
	if (iter != mLostSpeakers.end())
	{
		mLostSpeakers.erase(iter);
	}

	iter = mSpeakers.find(identifier);
	if (iter != mSpeakers.end())
	{
		Speaker* speaker = iter->second;
		speaker->hangup();
		mSpeakers.erase(iter);

		CELL_DELETE speaker;
	}
}
//-----------------------------------------------------------------------
bool TalkService::isReady(const String& identifier)
{
	CELL_LOCK_MUTEX(mSpeakerMutex);

	Speakers::const_iterator iter = mSpeakers.find(identifier);
	return (iter != mSpeakers.end());
}
//-----------------------------------------------------------------------
bool TalkService::hasCalled(const String& identifier)
{
	CELL_LOCK_MUTEX(mSpeakerMutex);

	Speakers::const_iterator iter = mSpeakers.find(identifier);
	if (iter != mSpeakers.end())
	{
		return iter->second->isCalled();
	}

	return false;
}
//-----------------------------------------------------------------------
bool TalkService::talk(const String& identifier, Primitive& primitive)
{
	CELL_LOCK_MUTEX(mSpeakerMutex);

	Speakers::iterator iter = mSpeakers.find(identifier);
	if (iter != mSpeakers.end())
	{
		if ((iter->second)->isCalled())
		{
			return (iter->second)->speak(primitive);
		}
	}

	return false;
}
//-----------------------------------------------------------------------
bool TalkService::talk(const String& identifier, Dialect& dialect)
{
	Primitive primitive(Nucleus::getSingleton().getTagAsString());
	if (dialect.translate(primitive))
	{
		return talk(identifier, primitive);
	}

	return false;
}
//-----------------------------------------------------------------------
void TalkService::addListener(TalkListener* listener)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	ListenerList::const_iterator iter = std::find(mListeners.begin(), mListeners.end(), listener);
	if (iter == mListeners.end())
	{
		mListeners.push_back(listener);
	}
}
//-----------------------------------------------------------------------
void TalkService::removeListener(TalkListener* listener)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	mListeners.remove(listener);
}
//-----------------------------------------------------------------------
bool TalkService::activateWebService(void)
{
	if (mWebService != NULL)
		return true;

	mWebService = CELL_NEW TalkWebService();

	bool state = mWebService->startup();
	if (false == state)
	{
		CELL_DELETE mWebService;
		mWebService = NULL;
	}

	return state;
}
//-----------------------------------------------------------------------
void TalkService::deactivateWebService(void)
{
	if (mWebService != NULL)
	{
		mWebService->shutdown();
		CELL_DELETE mWebService;
		mWebService = NULL;
	}
}
//-----------------------------------------------------------------------
Session* TalkService::getSession(const String& tag) const
{
	CELL_LOCK_MUTEX(mSessionMutex);

	TagSessionMap::const_iterator iter = mTagSessionMap.find(tag);
	if (iter != mTagSessionMap.end())
	{
		return iter->second;
	}
	return NULL;
}
//-----------------------------------------------------------------------
TalkTracker* TalkService::requestCellet(Session* session, const String& tag, const String& identifier)
{
	TalkTracker* tracker = NULL;
	TalkSessionContext* ctx = NULL;
	Cellet* cellet = NULL;

	{
		CELL_LOCK_MUTEX(mSessionMutex);

		SessionContexts::const_iterator iter = mSessionContexts.find(session);
		if (iter == mSessionContexts.end())
		{
			// 非法的 Session
			return NULL;
		}

		// 添加 TAG 与 Session 映射关系
		mTagSessionMap.insert(TagSessionMap::value_type(tag, session));

		// 查找该 Session 里对应的会话追踪器
		ctx = iter->second;
		tracker = ctx->getTracker(tag);
	}

	if (NULL != tracker)
	{
		if (tracker->activeCellet != NULL && tracker->activeCellet->getFeature().getIdentifier() == identifier)
		{
			cellet = NULL;
		}
		else
		{
			cellet = Nucleus::getSingleton().getCellet(identifier);
			if (NULL != cellet)
			{
				// 更新活跃的 Cellet
				tracker->activeCellet = cellet;
			}
		}
	}
	else
	{
		// 当前 Tag 没有标示，添加新的标示
		tracker = ctx->addTracker(tag, session->getAddress());

		// 将消费者顶点加入到云图中
		mCloudGraph->insert(tracker->getEndpoint());

		cellet = Nucleus::getSingleton().getCellet(identifier);
		if (NULL != cellet)
		{
			// 设置活跃的 Cellet
			tracker->activeCellet = cellet;
		}
	}

	// 回调
	if (NULL != cellet)
	{
		cellet->contacted(tag);
	}

	return tracker;
}
//-----------------------------------------------------------------------
void TalkService::dialogueCellet(Session* session, const String& tag, const Primitive& primitive)
{
	TalkSessionContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mSessionMutex);

		SessionContexts::const_iterator iter = mSessionContexts.find(session);
		if (iter != mSessionContexts.end())
		{
			ctx = iter->second;
		}
	}

	// 处理消息不上锁
	if (NULL != ctx)
	{
		// 更新活跃时间戳
		ctx->tickTime = mTick;

		TalkTracker* tracker = ctx->getTracker(tag);
		if (NULL != tracker)
		{
			// 调用 Cellet 对话
			if (tracker->activeCellet != NULL)
			{
				// 设置原语的 Cellet
				primitive.contactCellet(tracker->activeCellet);
				// 回调 Cellet
				tracker->activeCellet->dialogue(tag, primitive);
			}
		}
	}
}
//-----------------------------------------------------------------------
bool TalkService::notice(const String& tag, Primitive& primitive)
{
	Session* session = NULL;
	TalkSessionContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mSessionMutex);

		TagSessionMap::const_iterator iter = mTagSessionMap.find(tag);
		if (iter != mTagSessionMap.end())
		{
			session = iter->second;
		}

		// 获得原始 Session 之后，获取会话上下文
		SessionContexts::const_iterator sciter = mSessionContexts.find(session);
		if (sciter != mSessionContexts.end())
		{
			ctx = sciter->second;
		}
	}

	uint datalen = 0;

	// 处理消息不上锁
	if (NULL != session)
	{
		Message message;
		char noticeCache[8192] = {0x0};

		if (NULL != ctx)
		{
			// 封装消息
			datalen = ctx->packetDialogue(noticeCache, primitive);
			if (datalen > 0)
				message.set(noticeCache, datalen);
		}

		if (datalen > 0)
		{
			session->write(&message);
		}
		else
		{
			// 错误处理
			char log[128] = {0x0};
			sprintf(log, "[CC] TalkService notice %s error: message data length is 0 .", tag.c_str());
			LoggerManager::getSingleton().log(log);
		}
	}

	return (NULL != session && datalen > 0);
}
//-----------------------------------------------------------------------
void TalkService::openSession(Session* session)
{
	Certificate* cert = CELL_NEW Certificate();
	cert->key = Util::randomString(8);
	cert->plaintext = cell::peek(session);

	CELL_LOCK_MUTEX(mSessionMutex);
	mUnidentifiedSessions.insert(SessionCertificates::value_type(session, cert));
}
//-----------------------------------------------------------------------
void TalkService::closeSession(Session* session)
{
	StringVector identifiers;
	StringVector tags;
	TalkSessionContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mSessionMutex);

		SessionContexts::iterator iter = mSessionContexts.find(session);
		if (iter != mSessionContexts.end())
		{
			ctx = iter->second;
		}
	}

	if (NULL != ctx)
	{
		// 获取所有 Talk Tacker Tag
		StringVector talkTrackerTags;
		ctx->listTrackerTags(talkTrackerTags);
		StringVector::iterator iiter, iend = talkTrackerTags.end();
		for (iiter = talkTrackerTags.begin(); iiter != iend; ++iiter)
		{
			// 获取 Talk Tracker
			TalkTracker* tracker = ctx->getTracker(*iiter);
			if (NULL == tracker)
			{
				continue;
			}

			// 添加记录
			if (tracker->activeCellet != NULL)
			{
				identifiers.push_back(tracker->activeCellet->getFeature().getIdentifier());
				tags.push_back(tracker->getTag());
			}

			// 从云图中删除
			mCloudGraph->erase(tracker->getEndpoint());

			{
				CELL_LOCK_MUTEX(mSessionMutex);

				// 删除映射表中的记录
				TagSessionMap::iterator rtsiter = mTagSessionMap.find(tracker->getTag());
				if (rtsiter != mTagSessionMap.end())
				{
					mTagSessionMap.erase(rtsiter);
				}
			}
		}

		{
			CELL_LOCK_MUTEX(mSessionMutex);

			// 销毁 SessionContext
			destroyContext(ctx);

			// 移除
			SessionContexts::iterator iter = mSessionContexts.find(session);
			if (iter != mSessionContexts.end())
			{
				mSessionContexts.erase(iter);
			}
		}
	}

	if (false == identifiers.empty())
	{
		// 回调监听器
		for (size_t i = 0, size = identifiers.size(); i < size; ++i)
		{
			Cellet* cellet = Nucleus::getSingleton().getCellet(identifiers[i]);
			if (NULL != cellet)
			{
				cellet->quitted(tags[i]);
			}
		}
	}

	{
		CELL_LOCK_MUTEX(mSessionMutex);

		// 删除非校验 Session
		SessionCertificates::iterator niter = mUnidentifiedSessions.find(session);
		if (niter != mUnidentifiedSessions.end())
		{
			Certificate* cert = niter->second;
			CELL_DELETE cert;
			mUnidentifiedSessions.erase(niter);
		}
	}
}
//-----------------------------------------------------------------------
void TalkService::acceptSession(Session* session)
{
	CELL_LOCK_MUTEX(mSessionMutex);

	// 从非校验列表中删除
	SessionCertificates::iterator niter = mUnidentifiedSessions.find(session);
	if (niter != mUnidentifiedSessions.end())
	{
		Certificate* cert = niter->second;
		CELL_DELETE cert;
		mUnidentifiedSessions.erase(niter);
	}

	// 添加 SessionContext
	TalkSessionContext* ctx = CELL_NEW TalkSessionContext();
	ctx->tickTime = mTick;
	mSessionContexts.insert(SessionContexts::value_type(session, ctx));
}
//-----------------------------------------------------------------------
void TalkService::rejectSession(Session* session)
{
	{
		CELL_LOCK_MUTEX(mSessionMutex);

		// 从非校验列表中删除
		SessionCertificates::iterator niter = mUnidentifiedSessions.find(session);
		if (niter != mUnidentifiedSessions.end())
		{
			Certificate* cert = niter->second;
			CELL_DELETE cert;
			mUnidentifiedSessions.erase(niter);
		}
	}

	char log[128] = {0x0};
	sprintf(log, "[CC] Talk service reject session: %s:%d",
		session->getAddress().getHostAddress().c_str(), session->getAddress().getPort());
	LoggerManager::getSingleton().log(log);

	// 关闭 Session
	mAcceptor->close(session);
}
//-----------------------------------------------------------------------
void TalkService::destroyContext(TalkSessionContext* context)
{
	uint64 time = Util::currentTimeMillis();

	if (false == mExpiredContexts.empty())
	{
		TalkSessionContext* ctx;

		SessionContextList list;

		SessionContextList::iterator citer, cend = mExpiredContexts.end();
		for (citer = mExpiredContexts.begin(); citer != cend; ++citer)
		{
			ctx = (*citer);
			if (time - ctx->expiredTime > 60000)
			{
				// 超期的上下文
				list.push_back(ctx);
			}
		}

		if (false == list.empty())
		{
			cend = list.end();
			for (citer = list.begin(); citer != cend; ++citer)
			{
				ctx = (*citer);
				SessionContextList::iterator find = std::find(mExpiredContexts.begin(), mExpiredContexts.end(), ctx);
				if (find != mExpiredContexts.end())
					mExpiredContexts.erase(find);

				CELL_DELETE ctx;
			}
			list.clear();
		}
	}

	SessionContextList::iterator iter = std::find(mExpiredContexts.begin(), mExpiredContexts.end(), context);
	if (iter == mExpiredContexts.end())
	{
		// 设置过期时间
		context->expiredTime = time;

		mExpiredContexts.push_back(context);
	}
}
//-----------------------------------------------------------------------
void TalkService::updateSessionTickTime(Session* session)
{
	CELL_LOCK_MUTEX(mSessionMutex);

	SessionContexts::iterator iter = mSessionContexts.find(session);
	if (iter != mSessionContexts.end())
	{
		TalkSessionContext* ctx = iter->second;
		ctx->tickTime = mTick;
	}
}
//-----------------------------------------------------------------------
TalkService::Certificate* TalkService::getCertificate(Session* session)
{
	CELL_LOCK_MUTEX(mSessionMutex);

	SessionCertificates::iterator iter = mUnidentifiedSessions.find(session);
	if (iter != mUnidentifiedSessions.end())
	{
		return iter->second;
	}
	return NULL;
}
//-----------------------------------------------------------------------
void TalkService::startupAddons(void)
{
	if (mFlashAddon == NULL)
		mFlashAddon = CELL_NEW FlashAddon();

	if (false == mFlashAddon->startup())
	{
		LoggerManager::getSingleton().log("Startup flash addon service failed!");
		CELL_DELETE mFlashAddon;
		mFlashAddon = NULL;
	}
}
//-----------------------------------------------------------------------
void TalkService::shutdownAddons(void)
{
	if (mFlashAddon != NULL)
	{
		mFlashAddon->shutdown();
		CELL_DELETE mFlashAddon;
		mFlashAddon = NULL;
	}
}
//---------------------------------------------------------------------------
bool TalkService::configProxy(Session* session)
{
	CELL_LOCK_MUTEX(mSessionMutex);

	SessionContexts::const_iterator iter = mSessionContexts.find(session);
	if (iter != mSessionContexts.end())
	{
		TalkSessionContext* ctx = iter->second;
		ctx->proxy = true;

		return true;
	}
	else
	{
		return false;
	}
}
//-----------------------------------------------------------------------
FORCEINLINE bool TalkService::isProxyMode(void) const
{
	return (NULL != mProxy && mProxy->isWorking());
}
//-----------------------------------------------------------------------
FORCEINLINE TalkProxy* TalkService::getProxy(void)
{
	return mProxy;
}
//-----------------------------------------------------------------------
void TalkService::fireListenerDialogue(const String& tag, const Primitive& primitive)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	ListenerList::const_iterator iter, end = mListeners.end();
	for (iter = mListeners.begin(); iter != end; ++iter)
	{
		(*iter)->dialogue(tag, primitive);
	}
}
//-----------------------------------------------------------------------
void TalkService::fireListenerContacted(const String& tag)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	ListenerList::const_iterator iter, end = mListeners.end();
	for (iter = mListeners.begin(); iter != end; ++iter)
	{
		(*iter)->contacted(tag);
	}
}
//-----------------------------------------------------------------------
void TalkService::fireListenerQuitted(const String& tag)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	ListenerList::const_iterator iter, end = mListeners.end();
	for (iter = mListeners.begin(); iter != end; ++iter)
	{
		(*iter)->quitted(tag);
	}
}
//-----------------------------------------------------------------------
void TalkService::fireListenerFailed(const String& identifier)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	ListenerList::const_iterator iter, end = mListeners.end();
	for (iter = mListeners.begin(); iter != end; ++iter)
	{
		(*iter)->failed(identifier);
	}
}
//-----------------------------------------------------------------------
void TalkService::prepared(Runnable* command)
{
	// Nothing
}
//-----------------------------------------------------------------------
void TalkService::executed(Runnable* command)
{
	ActionDelegateWorker* worker = dynamic_cast<ActionDelegateWorker*>(command);
	CELL_DELETE worker;
}


//-----------------------------------------------------------------------
TalkService::Certificate::Certificate(void) : checked(false)
{
	time = Util::currentTimeMillis();
}
//-----------------------------------------------------------------------
TalkService::Certificate::~Certificate(void)
{
}

} // end namespace cell
